home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume5 / grabchars1.3 < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  34.2 KB

  1. Path: xanth!ames!oliveb!pyramid!decwrl!hplabs!hpda!hpwala!cfisun!ima!mirror!necntc!ncoast!allbery
  2. From: daniel@island.UUCP (Dan Smith, Release 28.0)
  3. Newsgroups: comp.sources.misc
  4. Subject: v05i073: grabchars 1.3, get/filter keystrokes directly from user (BSD)
  5. Message-ID: <8812060537.AA03805@island.uucp>
  6. Date: 7 Dec 88 00:43:23 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: daniel@island.UUCP (Dan Smith, Release 28.0)
  9. Lines: 1368
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 5, Issue 73
  13. Submitted-by: "Dan Smith, Release 28.0" <daniel@island.UUCP>
  14. Archive-name: grabchars1.3
  15.  
  16.     "grabchars" gets one or more keystrokes from the user, without
  17. requiring them to hit return.  It was written to make shell scripts
  18. (doesn't matter what type) more interactive.
  19.  
  20.     I know that it works fine on Suns running SUN OS 3.2-3.5,
  21. and a Vax 11/750 running Mt. Xinu 4.3 BSD.  I don't have support
  22. for SYS V or VMS or anything else like that yet; send me patches...
  23. Installation should be pretty straighforward, read the README and
  24. run Config.
  25.  
  26.     You'll find uses for this in all sorts of places.  The prime
  27. candidate is in your .login file, it's easy to use this to select different
  28. options.  I've provided a "demo" csh script which runs through many of the
  29. options.  For the most part, grabchars can replace the use of "$<" in
  30. csh scripts and "read" in sh scripts, and offer filtering, timeouts, and
  31. default answers - the exception at the moment is in trying to read control
  32. characters.
  33.  
  34.     Enjoy, and send me your comments/suggestions.  2.0 will provide
  35. SYS V support.
  36.  
  37.                 dan
  38.  
  39. DanSmith IslandGraphics 4000CivicCenterDr SanRafael MarinCo CA 94903 4154911000
  40. 415 332 FAST(h) 491 0402(Fax)|d: Nobodys' fault but mine| UnixFeastsMusicFilm
  41. daniel@island.uu.net   unicom!daniel@pacbell.com  {lll-crg,apple}!well!dansmith
  42.  
  43. ------------------------ snip -------- cut ------- chop ---------
  44. #! /bin/sh
  45. # This is a shell archive, meaning:
  46. # 1. Remove everything above the #! /bin/sh line.
  47. # 2. Save the resulting text in a file.
  48. # 3. Execute the file with /bin/sh (not csh) to create:
  49. #    README
  50. #    Config
  51. #    TODO
  52. #    Makefile.dist
  53. #    demo
  54. #    grabchars.1
  55. #    globals.c
  56. #    grabchars.c
  57. #    sys.c
  58. #    grabchars.h
  59. # This archive created: Mon Dec  5 19:52:34 1988
  60. # By:    Dan "Bucko" Smith ()
  61. export PATH; PATH=/bin:/usr/bin:$PATH
  62. echo shar: "extracting 'README'" '(3940 characters)'
  63. if test -f 'README'
  64. then
  65.        echo shar: "will not over-write existing file 'README'"
  66. else
  67. cat << \SHAR_EOF > 'README'
  68.                        Grabchars 1.3
  69.  
  70.         Copyright (c) 1988, Dan Smith
  71.  
  72. What this is:
  73.  
  74.     "grabchars" gets one or more keystrokes from the user, without
  75. requiring them to hit return.  It was written to make shell scripts
  76. (doesn't matter what type) more interactive.
  77.  
  78.     I know that it works fine on Suns running SUN OS 3.2-3.5,
  79. and a Vax 11/750 running Mt. Xinu 4.3 BSD.  I don't have support
  80. for SYS V or VMS or anything else like that yet; send me patches...
  81.  
  82.     You'll find uses for this in all sorts of places.  The prime
  83. candidate is in your .login file, it's easy to use this to select different
  84. options.  I've provided a "demo" csh script which runs through many of the
  85. options.  For the most part, grabchars can replace the use of "$<" in
  86. csh scripts and "read" in sh scripts, and offer filtering, timeouts, and
  87. default answers - the exception at the moment is in trying to read control
  88. characters.
  89.  
  90. Putting this together:
  91.  
  92.     Run Config; it will figure out where you might want to
  93. put the executable and the man page.  It will also put you into an
  94. editor with the Makefile, and then it will run a "make clean",
  95. "make depend", and a "make release".  You will need getopt (3)
  96. to compile this program.  If you're not sure if you have this, try
  97. "nm /lib/libc.a | grep getopt".  Get a Public Domain version if you
  98. don't (write me if you get really stuck, I have it).
  99.  
  100. Usage: (see the man page for more...)
  101.  
  102.     grabchars            gets one keystroke
  103.     grabchars -b            output to stdout and stderr
  104.     grabchars -c<valid characters>  only <valid chars> are returned
  105.     grabchars -d<char(s)>        default char or string to return
  106.     grabchars -e            output to stderr instead of stdout
  107.     grabchars -f            flush any previous input
  108.     grabchars -h            help screen
  109.     grabchars -n<number>        number of characters to read
  110.     grabchars -p<prompt>        prompt to help user
  111.     grabchars -q<prompt>        prompt to help user (through stderr)
  112.     grabchars -r            RETURN exits (use with -n)
  113.     grabchars -s            silent, just return status
  114.     grabchars -t<seconds>        timeout after <seconds>
  115.     grabchars -E            erase/kill character processing
  116.  
  117.     examples: (values to arguments can be in the same word or the next one)
  118.  
  119.     grabchars -caeiou     or
  120.     grabchars -c aeiou        get one of the vowels
  121.     grabchars -c i            get the letter 'i'
  122.     grabchars '-penter a letter '    print the prompt "enter a letter "
  123.     grabchars '-qenter a letter '    print the prompt ('q' for question)
  124.                     "enter a letter " through stderr...
  125.     grabchars -n4            get four characters
  126.     grabchars -t2            timeout after two seconds
  127.  
  128.     print a prompt and grab three characters...
  129.     grabchars -p 'enter three characters >> ' -n 3
  130.  
  131.     get two numbers with a ten second timeout...
  132.     grabchars -c 0123456789 -n2 -t10
  133.  
  134.     note that arguments like "-n4" or "-n 4" are handled the same way
  135.  
  136.     grabchars -h            will give a usage screen...
  137.  
  138. Legal paragraph:
  139.  
  140.     Grabchars may be freely copied, changed, and used, in whole or
  141. in part.  Don't try to make any money off of it.  Don't remove my headers.
  142. Don't say you wrote it.  This kit should be kept freely available, disk
  143. space permitting.  Not responsible for mishaps arising out of the use
  144. of this program, on the other hand, I haven't run into any problems with
  145. this. Lastly, Do not use any part of grabchars in any commercial product.
  146. Let's change the subject :-)
  147.  
  148. Patches and things like that:
  149.  
  150.     "Help! Save The World!" (LW)...if you make any modifications
  151. to grabchars, send me a diff suitable for use with the patch program.
  152. I don't want ten different versions of this running around.  I need to
  153. know what changes need to be made to get this to run on Sys V and other
  154. Unix (or other) variants.  I don't use them, so at this point I don't
  155. know!
  156.  
  157. Where to reach me:
  158.  
  159.     Dan Smith
  160.     Island Graphics
  161.     4000 Civic Center Drive
  162.     San Rafael, Ca 94903
  163.     +1 (415) 491 1000 (w), 491 0402 (fax), 332 3278 (h)
  164.  
  165.     daniel@island.uu.net or    
  166.     {pixar,grenada,ucbvax!ucbcad,unicom,well,sun,uunet}!island!daniel
  167.  
  168.     unicom!daniel@pacbell.com
  169.  
  170.     {apple,lll-crg}!well!dansmith
  171.  
  172. SHAR_EOF
  173. fi
  174. echo shar: "extracting 'Config'" '(2396 characters)'
  175. if test -f 'Config'
  176. then
  177.        echo shar: "will not over-write existing file 'Config'"
  178. else
  179. cat << \SHAR_EOF > 'Config'
  180. #!/bin/csh -f
  181. #
  182. #    $Header: Config,v 1.3 88/12/05 19:45:39 daniel grabchars_1_3 $
  183. #
  184. #    Config - set up Makefile for grabchars
  185. #
  186. #    Dan Smith (daniel@island.uu.net), November 1988
  187. #
  188. #    Config file for grabchars... must be csh, no attempt
  189. #    made to be eunice (i.e. echo " ") compatible...
  190. #
  191. clear
  192. cat << GUMBY
  193.  
  194.     Config for grabchars
  195.  
  196.     This csh script will figure out a few things about your
  197. system, and then will run a "make clean", a "make depend", and
  198. a "make release".  You should then try out grabchars, and, once assured
  199. that it's behaving itself, you should run a "make install"
  200.  
  201. GUMBY
  202. echo -n 'press return to start...'
  203. set ignore=$<
  204.  
  205. #    figure out where to put this when the user types
  206. #    "make install"...we'll try in three likely places...
  207.  
  208. foreach try_bin (/usr/local{/bin,} /usr/public/bin)
  209.     echo -n looking at $try_bin...
  210.     if (-w $try_bin) then
  211.         set bin_dir=$try_bin && echo yep... && break
  212.     endif
  213.     echo ""
  214. end
  215.  
  216. #    figure out where to put the man pages when the user
  217. #    "make install"...a few places come to mind...
  218.  
  219. foreach try_man (/usr/{,local/,public/}man/man1)
  220.     echo -n looking at $try_man...
  221.     if (-w $try_man) then
  222.         set man_dir=$try_man && echo yep... && break
  223.     endif
  224.     echo ""
  225. end
  226.  
  227. if ($?bin_dir) then
  228.     echo BIN_DIR looks like it will be $bin_dir
  229. else
  230.     echo BIN_DIR is unknown...check the Makefile when it comes up...
  231.     set bin_dir=""
  232. endif
  233.  
  234. if ($?man_dir) then
  235.     echo MAN_DIR looks like it will be $man_dir
  236. else
  237.     echo MAN_DIR is unknown...check the Makefile when it comes up...
  238.     set man_dir=""
  239. endif
  240.  
  241. set myedit=vi
  242. if ($?EDITOR) then
  243.     set myedit=$EDITOR
  244. endif
  245.  
  246. oh_really:
  247.     if (! -e $myedit) then
  248.         echo -n "I don't see a $myedit...where is your editor? "
  249.         set myedit=$<
  250.         echo ok...
  251.     endif
  252.  
  253. echo editor of choice seems to be \"$myedit\"...
  254.  
  255. if  (-e Makefile) mv Makefile{,.old} >& /dev/null
  256.  
  257. echo making makefile...
  258. sed    -e "s+^BIN_DIR.*+BIN_DIR = $bin_dir+" \
  259.     -e "s+^MAN_DIR.*+MAN_DIR = $man_dir+" \
  260.     -e "s+^EDITOR.*+EDITOR = $myedit+" \
  261.     < Makefile.dist > Makefile
  262.  
  263. echo going to $myedit with Makefile for you to check out..
  264. echo -n press return...
  265. set ignore=$<
  266. $myedit Makefile || \
  267.     echo where is your editor\?\!\!  && goto oh_really
  268.  
  269. echo " "
  270. echo clean up any residue from before, doing a \"make clean\"
  271. sleep 2
  272. make clean
  273.  
  274. echo " "
  275. echo going to run a \"make depend\"...
  276. sleep 2
  277. make depend
  278.  
  279. echo " "
  280. echo ok, let\'s try to make this with \"make release\"
  281. sleep 2
  282. make release
  283. SHAR_EOF
  284. chmod +x 'Config'
  285. fi
  286. echo shar: "extracting 'TODO'" '(403 characters)'
  287. if test -f 'TODO'
  288. then
  289.        echo shar: "will not over-write existing file 'TODO'"
  290. else
  291. cat << \SHAR_EOF > 'TODO'
  292. TODO file...
  293.  
  294.     add SYS V code...
  295.  
  296.     add support for arrow keys handle control characters better...
  297.  
  298.     I have the code for this in my "phonemail" program (to be
  299.     posted soon).  I'm not sure what would constitute reasonable
  300.     return values (have negative values? values greater than 128?)
  301.     Is there a canonical return value list for keyboard events?
  302.  
  303.     stronger erase/kill processing...
  304.  
  305.     Thatzit for now...
  306.  
  307. SHAR_EOF
  308. fi
  309. echo shar: "extracting 'Makefile.dist'" '(2088 characters)'
  310. if test -f 'Makefile.dist'
  311. then
  312.        echo shar: "will not over-write existing file 'Makefile.dist'"
  313. else
  314. cat << \SHAR_EOF > 'Makefile.dist'
  315. #    $Header: Makefile.dist,v 1.3 88/12/05 19:45:47 daniel grabchars_1_3 $
  316. #
  317. #       Makefile for grabchars
  318. #
  319. #    Dan Smith (daniel@island.uu.net), November 1988
  320. #
  321. SRCS =    globals.c grabchars.c sys.c
  322. OBJS =    globals.o grabchars.o sys.o
  323. HDRS =    grabchars.h
  324. MAN_PAGE = grabchars.1
  325. OTHERS = README Config TODO Makefile.dist demo
  326. ALL_TEXT = $(OTHERS) $(MAN_PAGE) $(SRCS) $(HDRS)
  327.  
  328. #    where to put things...
  329. BIN_DIR =
  330. MAN_DIR =
  331.  
  332. #    for rcs...
  333. STATE = grabchars_1_3
  334. VERSION = 1.3
  335.  
  336. #    change to suit...
  337. PRINTER = -Pislandlw
  338. EDITOR = /usr/ucb/vi
  339.  
  340. #    if you have this, check the path.  If you don't, leave it alone...
  341. MKID = mkid
  342. SHAR = shar -v
  343.  
  344. CC = cc
  345. CFLAGS = -g
  346.  
  347. #    defines...
  348. #
  349. #    BSD is mandatory for now...if you patch for SYS V please
  350. #    #ifdef for "SYS_V" in init_term (), handle_erase (),
  351. #    and lets_go ()...
  352. #
  353. #    DV_ERASE is my friends stab at putting erase/kill processing
  354. #    in this.  I haven't thoroughly tested it (-E option)
  355. DEFS = -DBSD -DDV_ERASE
  356.  
  357. #    force this, leave csh out of it...
  358. SHELL=/bin/sh
  359.  
  360. .c.o:
  361.     $(CC) -c $(CFLAGS) $(DEFS) $*.c
  362.  
  363. all: grabchars
  364.  
  365. release:
  366.     @make CFLAGS=-O all
  367.  
  368. grabchars: $(OBJS)
  369.     - mv grabchars grabchars.old 2>/dev/null
  370.     @echo loading...
  371.     $(CC) $(CFLAGS) $(OBJS)  -o grabchars
  372.     @echo done...
  373.  
  374. install: release
  375.     - cp grabchars $(BIN_DIR)
  376.     - cp grabchars.1 $(MAN_DIR) && echo "preparing man page" \
  377.     && man grabchars
  378.  
  379. id: $(SRCS) $(HDRS)
  380.     - $(MKID) $(SRCS) $(HDRS) || echo $(MKID) not available...
  381.  
  382. e: $(SRCS) $(HDRS)
  383.     $(EDITOR) $(SRCS) $(HDRS) Makefile
  384.  
  385. pgrind:
  386.     @echo pgrinding out sources...
  387.     lpq $(PRINTER)
  388.     pgrind $(SRCS) $(HDRS) Makefile
  389.  
  390. rcs:
  391.     @echo checking grabchars in to RCS...
  392.     ci -s$(STATE) -r$(VERSION) -f -u $(ALL_TEXT)
  393.  
  394. shar:
  395.     @echo bundling up grabchars for transit...
  396.     $(SHAR) $(ALL_TEXT) > grabchars.shar
  397.  
  398. clean: id tags
  399.     - touch $(OBJS) grabchars
  400.     - /bin/rm $(OBJS) grabchars
  401.  
  402. depend: 
  403.     @echo making dependencies...
  404.     sed -n '1,/^#    lines after this point/p' Makefile >.depends &&\
  405.     cc -M $(SRCS) | tee /dev/tty >> .depends && mv .depends Makefile
  406.  
  407. tags: $(SRCS)
  408.     ctags $(SRCS)
  409.  
  410. #       lines after this point produced with cc -M, leave this line here
  411. SHAR_EOF
  412. fi
  413. echo shar: "extracting 'demo'" '(1881 characters)'
  414. if test -f 'demo'
  415. then
  416.        echo shar: "will not over-write existing file 'demo'"
  417. else
  418. cat << \SHAR_EOF > 'demo'
  419. #!/bin/csh -f
  420. clear
  421. cat << GUMBY
  422.  
  423.     Grabchars demo...
  424.  
  425.     get one character with "grabchars"
  426. GUMBY
  427. grabchars
  428. echo " status returned was $status"
  429.  
  430. cat << POKEY
  431.  
  432.     grab a vowel with "grabchars -caeiou"
  433.  
  434.     Type something that isn't a vowel at first...
  435.  
  436. POKEY
  437. grabchars -caeiou
  438. echo " status returned was $status"
  439.  
  440. cat << WILMA
  441.  
  442.     prompt the user  with "grabchars -p 'give me any character >> '"
  443. WILMA
  444. grabchars -p 'give me any character >> '
  445. echo " status returned was $status"
  446.  
  447. cat << FRED
  448.  
  449.     prompt through stderr  with "grabchars -q 'give me any character >> '",
  450. so that we can set the variable "user_char"...
  451. FRED
  452. set user_char=`grabchars -q 'give me any character >> '`
  453. echo " status returned was $status"
  454. echo '$user_char = '$user_char
  455.  
  456. cat << BETTY
  457.  
  458.     enter three characters...  "grabchars -n3"
  459.  
  460. BETTY
  461. grabchars -n3
  462. echo " status returned was $status"
  463.  
  464. cat <<  BARNEY
  465.  
  466.     enter 10 characters within 3 seconds... "grabchars -n10 -t3"
  467.  
  468.  
  469. BARNEY
  470. grabchars -n10 -t3
  471. set really_typed=$status
  472. if ($really_typed == 10) then
  473.     echo 'hey\! you got 10\!?'
  474. else
  475.     echo "    $really_typed returned...means that grabchars timed out..."
  476. endif
  477.  
  478. def_test:
  479. cat << RADRED
  480.  
  481.     let the user pick a default...
  482.     using "grabchars -d yes -p 'just hit return '...
  483.  
  484. RADRED
  485. #    the '-f' here is used to flush any previous input...
  486. grabchars -f -d yes -p 'just hit return '
  487. if ($status != 3) then
  488.     echo whoops\!  Let\'s try that again...
  489.     goto def_test
  490. endif
  491.  
  492. cat << MUSKRAT
  493.  
  494.     same idea, but let this timeout in four seconds...
  495.     using "grabchars -f -d always -t 4"
  496.  
  497.     (don't type anything...)
  498.  
  499. MUSKRAT
  500. grabchars -f -d always -t 4
  501.  
  502. cat << PEBBLES
  503.  
  504.  
  505.     The last one...  get two numbers with a ten second timeout...
  506.     trying "grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
  507.  
  508. PEBBLES
  509. grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
  510. echo " status returned was $status"
  511. echo ""
  512. echo test/demo done...enjoy\!
  513. SHAR_EOF
  514. chmod +x 'demo'
  515. fi
  516. echo shar: "extracting 'grabchars.1'" '(4786 characters)'
  517. if test -f 'grabchars.1'
  518. then
  519.        echo shar: "will not over-write existing file 'grabchars.1'"
  520. else
  521. cat << \SHAR_EOF > 'grabchars.1'
  522. ''' Man page for grabchars, uses Larry Wall's "patch" man page as
  523. ''' a template.
  524. .de Sh
  525. .br
  526. .ne 5
  527. .PP
  528. \fB\\$1\fR
  529. .PP
  530. ..
  531. .de Sp
  532. .if t .sp .5v
  533. .if n .sp
  534. ..
  535. '''
  536. '''     Set up \*(-- to give an unbreakable dash;
  537. '''     string Tr holds user defined translation string.
  538. '''     Bell System Logo is used as a dummy character.
  539. '''
  540. .ie n \{\
  541. .tr \(bs-\*(Tr
  542. .ds -- \(bs-
  543. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  544. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  545. .ds L" ""
  546. .ds R" ""
  547. .ds L' '
  548. .ds R' '
  549. 'br\}
  550. .el\{\
  551. .ds -- \(em\|
  552. .tr \*(Tr
  553. .ds L" ``
  554. .ds R" ''
  555. .ds L' `
  556. .ds R' '
  557. 'br\}
  558. .TH GRABCHARS 1 LOCAL
  559. .SH NAME
  560. grabchars - get keystrokes directly from user
  561. .SH SYNOPSIS
  562. .B grabchars
  563. [options]
  564. .SH DESCRIPTION
  565. \fBGrabchars\fP gets characters from the user as they are
  566. typed in, without having to wait for the return key to
  567. be pressed.  Among other things, this allows shell scripts
  568. to be written with highly interactive menus.
  569. .PP
  570. By default,
  571. .I grabchars
  572. will obtain one character from stdin, echo that character to stdout,
  573. and return with a status of one; meaning one character read.
  574. .TP 5
  575. .B \-b
  576. Both
  577. .I stdout
  578. and
  579. .I stderr
  580. are used for output.  This is useful for setting a variable in
  581. a shell script and echoing a keystroke to the screen at the
  582. same time.
  583. .TP 5
  584. .B \-c<valid characters>
  585. Only characters in
  586. .I <valid characters>
  587. are accepted.  Regular expressions such as [a-z]
  588. may be used to specify ranges.  All other characters are ignored.
  589. .TP 5
  590. .B \-d<char(s)>
  591. Default char or string to output if the user hits
  592. .B RETURN
  593. or lets
  594. .B grabchars
  595. timeout.  The status that is returned is the same as if the user had
  596. typed in the character or string, so this option may be used with
  597. the
  598. .B \-s
  599. (silent) flag.
  600. .TP 5
  601. .B \-e
  602. Output goes to
  603. .I stderr
  604. rather than
  605. .I stdout.
  606. .TP 5
  607. .B \-f
  608. Flush any previous input.  By default,
  609. .I grabchars
  610. will see any characters present in
  611. .I stdin,
  612. which allows for some typeahead in shell scripts.
  613. .TP 5
  614. .B \-h
  615. Help/usage screen.
  616. .TP 5
  617. .B \-p<prompt>
  618. Sets up a prompt for the user.  See
  619. .I EXAMPLES.
  620. .TP 5
  621. .B \-q<prompt>
  622. Sets up a prompt for the user, except it is printed to
  623. .I stderr
  624. rather than
  625. .I stdout.
  626. .TP 5
  627. .B \-r
  628. The
  629. .B RETURN
  630. key exits.  Use this with the -n option to allow for variable
  631. numbers of characters to be typed in.
  632. .TP 5
  633. .B \-n<number>
  634. Number of characters to read.  By default,
  635. .I grabchars
  636. looks for one character.
  637. .TP 5
  638. .B \-s
  639. Silent.  Do not output anything. Just return a status.
  640. .TP 5
  641. .B \-t<seconds>
  642. Time to allow the user to respond.  By default, the user
  643. can take as long as he or she wants to.  The timeout option allows
  644. you to write shell scripts where you can offer some assistance
  645. if it's obvious that the user might be stuck.
  646. .TP 5
  647. .B \-E
  648. Erase/kill processing is done.  You have use of the keys (usually
  649. DELETE and ^U or ^X) that you would normally have from the
  650. shell for deleting characters.  This is useful with the
  651. .B \-n
  652. option, where many characters are being typed in.  This code hasn't
  653. been thoroughly tested.
  654. .SH EXAMPLES
  655. .TP 5
  656. .B grabchars
  657. gets one keystroke
  658. .TP 5
  659. .B grabchars \-caeiou
  660. get one of the vowels
  661. .TP 5
  662. .B grabchars -c i
  663. get the letter 'i'
  664. .TP 5
  665. .B grabchars '\-penter a letter '
  666. print the prompt "enter a letter "
  667. .TP 5
  668. .B grabchars '\-qenter a letter '
  669. print the prompt ('q' for question) "enter a letter " through
  670. .I stderr.
  671. .TP 5
  672. .B grabchars \-n4
  673. get four characters.
  674. .TP 5
  675. .B grabchars \-d a
  676. If the first character typed is a
  677. .B RETURN,
  678. pretend it was an 'a'.
  679. .TP 5
  680. .B grabchars \-d gumby
  681. If the first character typed is a
  682. .B RETURN,
  683. pretend that the user typed in "gumby".
  684. .TP 5
  685. .B grabchars \-r
  686. The
  687. .B RETURN
  688. key will exit
  689. .I grabchars.  You would use this with the
  690. .B -n
  691. option, so that variable numbers of characters may be entered.
  692. .TP
  693. .B grabchars \-n 4 \-r \-t 10
  694. Accept up to four characters, or exit when
  695. .B RETURN
  696. is hit, or exit when 10 seconds have elapsed.
  697. .TP 5
  698. .B grabchars \-t2
  699. timeout after two seconds.
  700. .TP 5
  701. .B grabchars \-d gumby \-t2
  702. If the first character typed is a
  703. .B RETURN,
  704. or if two seconds have gone by,
  705. pretend that the user typed in "gumby".
  706. .TP 5
  707. .B grabchars \-n3 \-p 'initials: '
  708. print a prompt and grab three characters.
  709. .TP 5
  710. .B grabchars \-c 0123456789 \-n2 \-t10
  711. get two numbers with a ten second timeout.
  712. .PP
  713. note that arguments like "-n4" or "-n 4" are handled the same way
  714. .SH SEE ALSO
  715. csh(1) and sh(1)
  716. for syntax of
  717. .I csh
  718. and
  719. .I sh
  720. scripts, respectively.
  721. See "The Unix Csh Field Guide", by Gail and Paul Anderson (Prentice Hall),
  722. for an excellent tour of csh and good examples of writing csh scripts.
  723. .SH DIAGNOSTICS
  724. .I
  725. Grabchars
  726. returns
  727. .B \-2
  728. if it times out, or
  729. .B \-1
  730. if it gives a usage statement.  Otherwise, it
  731. returns the number of characters successfully read.
  732. .SH AUTHOR
  733. .nf
  734. Dan Smith (daniel@island.uu.net or {ucbvax!ucbcad,well,sun}!island!daniel)
  735. SHAR_EOF
  736. fi
  737. echo shar: "extracting 'globals.c'" '(1778 characters)'
  738. if test -f 'globals.c'
  739. then
  740.        echo shar: "will not over-write existing file 'globals.c'"
  741. else
  742. cat << \SHAR_EOF > 'globals.c'
  743. /*
  744. **    $Header: globals.c,v 1.3 88/12/05 19:46:01 daniel grabchars_1_3 $
  745. **
  746. **    globals.c - declare global variables for grabchars
  747. **
  748. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  749. */
  750. #include <stdio.h>
  751. #include "grabchars.h"    /* where we typedef FLAGS */
  752.  
  753. FILE *outfile, *otherout;
  754. FLAG *flags;
  755.  
  756. int exit_stat;
  757. char valid_chars[128], default_string[128];
  758.  
  759. #ifdef DV_ERASE
  760. char *erase_buf;    /* DV: Malloc'ed later */
  761. #endif
  762.  
  763. /*
  764. **    this gets in the way sitting in grabchars.c, so I moved it here.
  765. **    If you add anything, keep in mind that you're trying to squeeze
  766. **    everything onto a 24 line window/terminal... The "-h" doc
  767. **    is just a convenience, any option that grabchars doesn't already
  768. **    use will give the help screen...
  769. */
  770. char *usage_statement[] = {
  771. "usage: grabchars        gets one keystroke",
  772. "    -b            output to stdout and stderr",
  773. "    -c<valid characters>    only <valid chars> are returned",
  774. "    -d<char(s)>        default char or string to return",
  775. "    -e            output to stderr instead of stdout",
  776. "    -f            flush any previous input before reading",
  777. "    -h            help screen",
  778. "    -n<number>        number of characters to read",
  779. "    -p<prompt>        prompt to help user",
  780. "    -q<prompt>        prompt to help user (through stderr)",
  781. "    -r            RETURN key exits (use with -n)",
  782. "    -s            silent, just return status",
  783. "    -t<seconds>        timeout after <seconds>",
  784. "    -E            honor erase/kill characters", /* DV */
  785. "examples: (values to arguments can be in the same word or the next one)",
  786. "grabchars -c aeiou        get one of the vowels",
  787. "grabchars -c i            get the letter 'i'",
  788. "grabchars '-penter a letter '    print the prompt \"enter a letter \"",
  789. "grabchars -n4            get four characters",
  790. "grabchars -t2            timeout after two seconds",
  791. " ",
  792. "print a prompt and grab three characters...",
  793. "grabchars -p 'enter three characters >> ' -n 3",
  794. 0
  795. };
  796. SHAR_EOF
  797. fi
  798. echo shar: "extracting 'grabchars.c'" '(8500 characters)'
  799. if test -f 'grabchars.c'
  800. then
  801.        echo shar: "will not over-write existing file 'grabchars.c'"
  802. else
  803. cat << \SHAR_EOF > 'grabchars.c'
  804. /*
  805. **    $Header: grabchars.c,v 1.3 88/12/05 19:46:06 daniel grabchars_1_3 $
  806. **
  807. **    grabchars.c    - get characters directly from the user
  808. **
  809. **    Dan Smith (daniel@island.uu.net), October 23, 1988
  810. **
  811. **    This program grabs characters from the user as they are
  812. **    typed in, without having to wait for the return key to
  813. **    be pressed.  Among other things, this allows shell scripts
  814. **    to be written with highly interactive menus...
  815. **
  816. **    [to jump right to the code, search for "start of grabchars"]
  817. **
  818. **    Usage rundown:
  819. **
  820. **    grabchars            gets one keystroke
  821. **    grabchars -b            output to stdout and stderr
  822. **    grabchars -c<valid characters>  only <valid chars> are returned
  823. **    grabchars -d<char(s)>        default char or string to return
  824. **    grabchars -e            output to stderr instead of stdout
  825. **    grabchars -f            flush any previous input
  826. **    grabchars -h            help screen
  827. **    grabchars -n<number>        number of characters to read
  828. **    grabchars -p<prompt>        prompt to help user
  829. **    grabchars -q<prompt>        prompt to help user (through stderr)
  830. **    grabchars -r            RETURN key exits (use with -n)
  831. **    grabchars -s            silent, just return status
  832. **    grabchars -t<seconds>        timeout after <seconds>
  833. **    grabchars -E            erase/kill character processing
  834. **
  835. **    examples: (values to arguments can be in the same word or the next one)
  836. **
  837. **    grabchars -caeiou     or
  838. **    grabchars -c aeiou        get one of the vowels
  839. **    grabchars -c i            get the letter 'i'
  840. **    grabchars '-penter a letter '    print the prompt "enter a letter "
  841. **    grabchars '-qenter a letter '    print the prompt ('q' for question)
  842. **                    "enter a letter " through stderr...
  843. **    grabchars -n4            get four characters
  844. **    grabchars -t2            timeout after two seconds
  845. **
  846. **    print a prompt and grab three characters...
  847. **    grabchars -p 'enter three characters >> ' -n 3
  848. **
  849. **    get two numbers with a ten second timeout...
  850. **    grabchars -c 0123456789 -n2 -t10
  851. **
  852. **    note that arguments like "-n4" or "-n 4" are handled the same way
  853. **
  854. **    History:
  855. **    
  856. **    Oct 1988: versions 1.0 - 1.1
  857. **
  858. **    November 6, 1988 (1.15)
  859. **    added -f flag to flush input, default is to use    TIOCSETN instead
  860. **    of TIOCSETP
  861. **
  862. **    November 22, 1988 (1.16)
  863. **    added -d flag for a default character or string to use if the
  864. **    user hits return first thing or times out.  handle_default ()
  865. **    was added at this time
  866. **
  867. **    November 23, 1988 (1.19)
  868. **    added -r flag to exit when RETURN is hit.  This was suggested by
  869. **    David Vezie.
  870. **
  871. **    November 29, 1988 (1.2)
  872. **    Disaster strikes...I was updating Makefile.dist, and copied SRCS
  873. **    to OBJS, and forgot to change grabchars.c to grabchars.o, and
  874. **    then (after Config) did a "make clean"!  I realized that I did not
  875. **    have a backup, but fortunately had David Vezie's hack of grabchars.c
  876. **    from a few days ago (he had added erase/line kill character processing)
  877. **    ...moral: use RCS, check your Makefiles!  Used this as an opportunity
  878. **    to split things up into grabchars.h, globals.c,    and sys.c
  879. **    Got -c to handle ranges (via re_comp() and re_exec())
  880. */
  881.  
  882. /*    start of grabchars... */
  883. #include <stdio.h>
  884. #include <signal.h>
  885. #include "grabchars.h"
  886.  
  887. /*    see globals.c */
  888. extern FILE *outfile, *otherout;
  889. extern FLAG *flags;
  890. extern int exit_stat;
  891. extern char *usage_statement[];
  892.  
  893. /*
  894. **    David Vezie (island!r2d2!dv) took a great shot at putting in
  895. **    erase/kill processing.  I need to test this some more, and I'll
  896. **    most likely change it a bit.  I put DV_ERASE in the Makefile
  897. **    as a default; take it out if it misbehaves :-)
  898. */
  899. #ifdef DV_ERASE
  900. extern char *erase_buf;    /* DV: Malloc'ed later */
  901. #endif
  902.  
  903. main (argc, argv)
  904. int argc;
  905. register char **argv;
  906. {
  907.     /* two signal/wrapup handling routines in sys.c */
  908.     int lets_go (), overtime ();
  909.  
  910.     /* for -d option */
  911.     void handle_default ();
  912.  
  913.     /* for getopt () */
  914.     extern int optind, opterr;
  915.     extern char *optarg;
  916.     char comarg;
  917.  
  918.     int how_many = 1;    /* how many chars to read */
  919.     int num_read;        /* how many we have read... */
  920.     int timeout;        /* and an optional time to do it in... */
  921.     int i;            /* for usage_statement if we need it.. */
  922.  
  923.     /*
  924.     **    re_comp (), re_exec () let us do things
  925.     **    like "grabchars -c '[a-d]'" or "grabchars -c '[^a-z]'"...
  926.     */
  927.     char *re_comp (), *re_error;
  928.     extern char valid_chars[128], default_string[128];
  929.     char ch, check_str[2];
  930.  
  931.     alarm (0);
  932.     opterr = 0;
  933.     exit_stat = -1;    /* if we're interrupted, exit with this status */
  934.  
  935.     outfile = stdout;
  936.     otherout = stderr;
  937.     if ((flags = (FLAG *) malloc (sizeof (FLAG))) == (FLAG *) NULL) {
  938.         fprintf (stderr, "can't find enough memory...bye!\n");
  939.         exit (exit_stat);    /* we don't need lets_go () for this */
  940.     }
  941.  
  942.     init_flags ();
  943.     init_signal ();
  944.  
  945.     while ((comarg = getopt (argc, argv,  "befrsEc:d:n:p:q:t:")) != EOF) {
  946.         switch (comarg) {
  947.             case 'b':
  948.                 flags->both = 1;
  949.                 break;
  950.             case 'c':
  951.                 flags->check = 1;
  952.                 strcpy (valid_chars, optarg);
  953.                 if (strlen (optarg) == 0) {
  954.                     fprintf (stderr, "-c option: must have at least one valid character\n");
  955.                     exit (-1);
  956.                 }
  957.                 /*
  958.                 ** most of the time, grabchars can be
  959.                 ** called safely with things like
  960.                 ** "a-z", because we can check to
  961.                 ** see if we need to add brackets...
  962.                 */
  963.                 if (valid_chars[0] != '[' && 
  964.                 valid_chars[strlen (valid_chars) - 1] != ']')
  965.                     sprintf (valid_chars, "%c%s%c",
  966.                         '[', optarg, ']');
  967.  
  968.                 if ((re_error = re_comp (valid_chars))
  969.                                 != NULL) {
  970.                     fprintf (stderr,
  971.                         "-c option: %s\n", re_error);
  972.                     exit (-1);
  973.                 }
  974.                 break;
  975.             case 'd':
  976.                 flags->dflt = 1;
  977.                 strcpy (default_string, optarg);
  978.                 if (strlen (optarg) == 0) {
  979.                 fprintf (stderr, "-d option: must have at least one character for default\n");
  980.                     exit (-1);
  981.                 }
  982.                 break;
  983.             case 'e':
  984.                 outfile = stderr;
  985.                 otherout = stdout;
  986.                 break;
  987.             case 'f':
  988.                 flags->flush = 1;
  989.                 break;
  990.             case 'n':
  991.                 how_many = atoi (optarg);
  992.                 if (how_many <= 0) {
  993.                     fprintf (stderr, "-n option: number of characters to read must be greater than zero\n");
  994.                     exit (-1);
  995.                 }
  996.                 break;
  997.             case 'p':
  998.                 fprintf (stdout, "%s", optarg);
  999.                 break;
  1000.             case 'q':
  1001.                 fprintf (stderr, "%s", optarg);
  1002.                 break;
  1003.             case 'r':
  1004.                 flags->ret_key = 1;
  1005.                 break;
  1006.             case 's':
  1007.                 flags->silent = 1;
  1008.                 break;
  1009.             case 't':
  1010.                 timeout = atoi (optarg);
  1011.                 if (timeout <= 0) {
  1012.                     fprintf (stderr, "-t option: number of seconds to timeout must be greater than zero\n");
  1013.                     exit (-1);
  1014.                 }
  1015.  
  1016.                 /*
  1017.                 ** we must have some valid time >0 seconds to
  1018.                 ** get here, so we'll set an alarm...
  1019.                 */
  1020.                 signal (SIGALRM, overtime);
  1021.                 alarm ((unsigned int) timeout);
  1022.                 break;
  1023.             case 'E':    /* DV: honor erase/kill flag */
  1024. #ifdef DV_ERASE
  1025.                 flags->erase = 1;
  1026. #else
  1027.                 fprintf (stderr, "-E is disabled\n");
  1028.                 exit (-1);
  1029. #endif
  1030.                 break;
  1031.  
  1032.                 /*
  1033.                 ** I bet I could leave out "default", but
  1034.                 ** I also bet that all getopt () routines
  1035.                 ** are not created equal, so in it stays!
  1036.                 */
  1037.             case '?':
  1038.             default:
  1039.                 i = 0;
  1040.                 while (usage_statement[i])
  1041.                     puts (usage_statement[i++]);
  1042.                 exit (-1);
  1043.         }
  1044.     }
  1045.  
  1046.     /* we're still here, really running...now change the tty... */
  1047.     init_term ();
  1048.  
  1049. #ifdef DV_ERASE
  1050.     /* DV: malloc (okay, well calloc) space for the erase buffer */
  1051.     if (flags->erase) {
  1052.         /* We can't do it up in the switch, because we don't know
  1053.         ** how many is how_many
  1054.         */
  1055.         erase_buf = (char *)calloc (1, how_many);
  1056.         if (erase_buf == NULL) {
  1057.             fprintf (stderr,
  1058.             "Error:  Couldn't malloc space for erase buffer\n");
  1059.             exit_stat = -1;
  1060.             lets_go();
  1061.         }
  1062.     }
  1063. #endif
  1064.  
  1065.     for (num_read = 0; num_read < how_many; num_read++) {
  1066.         ch = getchar ();
  1067.  
  1068.         /* use default_string, this does *not* return */
  1069.         if (ch == '\n' && flags->dflt && num_read == 0)
  1070.             handle_default ();
  1071.  
  1072.         /*
  1073.         ** set by -r, a RETURN key gets us out (use with -n)
  1074.         ** suggested by David Vezie
  1075.         */
  1076.         if (ch == '\n' && flags->ret_key)
  1077.             break;
  1078.  
  1079.         /*    filter chars... */
  1080.         if (flags->check) {
  1081.             sprintf (check_str, "%c", ch);
  1082.             if (re_exec (check_str) != 1) {
  1083.                 num_read--;
  1084.                 continue;
  1085.             }
  1086.         }
  1087.  
  1088.         /*
  1089.         ** if we're just looking for a return status
  1090.         ** then have flags->silent set (-s)
  1091.         **
  1092.         ** DV: Also, we don't want to output yet,
  1093.         ** if we're processing erase/kill charfacters.
  1094.         */
  1095. #ifdef DV_ERASE
  1096.         if (! flags->silent && ! flags->erase) {
  1097. #else
  1098.         if (! flags->silent) { 
  1099. #endif
  1100.             putc (ch, outfile);
  1101.             if (flags->both)
  1102.                 putc (ch, otherout);
  1103.         }
  1104.  
  1105. #ifdef DV_ERASE
  1106.         if (flags->erase)
  1107.             handle_erase (ch, &num_read);
  1108. #endif
  1109.     }
  1110.  
  1111. #ifdef DV_ERASE
  1112.     if (flags->erase) {
  1113.         fprintf (outfile, "%s", erase_buf);
  1114.         if (flags->both)
  1115.             fprintf (otherout, "%s", erase_buf);
  1116.     }
  1117. #endif
  1118.  
  1119.     exit_stat = num_read;
  1120.     lets_go ();
  1121. }
  1122. SHAR_EOF
  1123. fi
  1124. echo shar: "extracting 'sys.c'" '(4386 characters)'
  1125. if test -f 'sys.c'
  1126. then
  1127.        echo shar: "will not over-write existing file 'sys.c'"
  1128. else
  1129. cat << \SHAR_EOF > 'sys.c'
  1130. /*
  1131. **    $Header: sys.c,v 1.3 88/12/05 19:46:14 daniel grabchars_1_3 $
  1132. **
  1133. **    sys.c - terminal routines for grabchars
  1134. **
  1135. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  1136. **
  1137. **    History:
  1138. **
  1139. **    December 2, 1988
  1140. **    made #ifdefs for DV_ERASE and BSD, wrote notes in handle_erase ()
  1141. **    for changes and improvements
  1142. */
  1143.  
  1144. #include <stdio.h>
  1145. #include <sgtty.h>
  1146. #include <signal.h>
  1147. #include "grabchars.h"
  1148.  
  1149. struct sgttyb orig, new;
  1150.  
  1151. /* all declared in globals.c */
  1152. extern FILE *outfile, *otherout;
  1153. extern FLAG *flags;
  1154. extern int exit_stat;
  1155. extern char default_string[128];
  1156.  
  1157. #ifdef DV_ERASE
  1158. extern char *erase_buf;
  1159. #endif
  1160.  
  1161. /* initialize global flags */
  1162. init_flags ()
  1163. {
  1164.     flags->both = 0;
  1165.     flags->check = 0;
  1166.     flags->dflt = 0;
  1167.     flags->flush = 0;
  1168.     flags->ret_key = 0;
  1169.     flags->silent = 0;
  1170.     flags->erase = 0;
  1171. }
  1172.  
  1173. /*
  1174. **    initialize tty
  1175. **
  1176. **    this really needs SYS V code...any patchers out there?
  1177. */
  1178. init_term ()
  1179. {
  1180.     /*    play havoc with the terminal :-) */
  1181.  
  1182. #ifdef BSD
  1183.     ioctl (0, TIOCGETP, &orig);
  1184.     new = orig;
  1185.     new.sg_flags &= ~ECHO;
  1186.     new.sg_flags |= CBREAK;
  1187.  
  1188.     (flags->flush) ? ioctl (0, TIOCSETP, &new) :    /* to flush... */
  1189.         ioctl (0, TIOCSETN, &new);        /* ...or not to flush */
  1190. #endif
  1191. }
  1192.  
  1193. /* handle the outside world */
  1194. init_signal ()
  1195. {
  1196.     int lets_go ();
  1197.  
  1198.     signal (SIGINT, lets_go);
  1199.     signal (SIGTSTP, lets_go);
  1200.     signal (SIGQUIT, lets_go);
  1201. }
  1202.  
  1203. /*
  1204. **    something's up with the user...give a useful exit status so
  1205. **    we can ask things like "do you need help?"
  1206. */
  1207. int overtime ()
  1208. {
  1209.     int lets_go ();
  1210.     void handle_default ();
  1211.  
  1212.     /* does not return */
  1213.     if (exit_stat == -1 && flags->dflt)
  1214.         handle_default ();
  1215.  
  1216.     exit_stat = -2;
  1217.     lets_go ();
  1218. }
  1219.  
  1220. /*
  1221. **    the default_flag is set, and the user either typed a return
  1222. **    or timed out.  This routine does not return.
  1223. */
  1224. void handle_default ()
  1225. {
  1226.     int lets_go ();
  1227.  
  1228.     if (! flags->silent) {
  1229.         fputs (default_string, outfile);
  1230.         if (flags->both)
  1231.             fputs (default_string, otherout);
  1232.     }
  1233.     exit_stat = strlen (default_string);
  1234.     lets_go ();
  1235. }
  1236.  
  1237. /*    clean up and get out of here... */
  1238. int lets_go ()
  1239. {
  1240. #ifdef BSD
  1241.     ioctl (0, TIOCSETP, &orig);
  1242. #endif
  1243.     exit (exit_stat);
  1244. }
  1245.  
  1246. #ifdef DV_ERASE
  1247.  
  1248. /*
  1249. **    December 2, 1988
  1250. **    Bucko's (daniel) in progress notes for changing this...
  1251. **
  1252. **    first time through processing should be called as its' own
  1253. **    function from the -E case in the main (getopt ()) switch...
  1254. **
  1255. **    stdout and stderr should never be affected by any erasures...
  1256. **    (they probably are not now, I haven't thoroughly tested this...)
  1257. **
  1258. **    I need to drag in my word erase routine; never can tell how
  1259. **    long some people are going to want their lines with -n! :-)
  1260. **
  1261. **    If someone wants a control char (via literal (^V)), we should
  1262. **    give it to them...this would be more compatible with $< (csh)
  1263. **    and read (sh)... grabchars almost completely replaces these
  1264. **    now.
  1265. **
  1266. **    we can also be sensitive to pipe/no pipe via isatty ()...
  1267. */
  1268.  
  1269. /*    DV: handle erase characters, kill characters, etc. */
  1270. handle_erase (ch, cnt)
  1271. char ch;
  1272. int *cnt;
  1273. {
  1274.     static char first = 1;
  1275.     static char erasec, killc, werasec, lnextc, rprntc;
  1276.     static char lnextflg = 0;
  1277.     static char *cp;
  1278.     static FILE *tty;
  1279.     int i;
  1280.  
  1281.     if (first) {
  1282.         /* initialize static things */
  1283.         struct sgttyb sb;
  1284.         struct ltchars ltc;
  1285.  
  1286.         first = 0;
  1287.         cp = erase_buf;
  1288.         tty = fopen ("/dev/tty", "w");
  1289.  
  1290.         /* . this isn't going to do... what if -e is set?...dan */
  1291.         if (tty == NULL)
  1292.             tty = stderr;
  1293.         ioctl (0, TIOCGETP, &sb);
  1294.         ioctl (0, TIOCGLTC, <c);
  1295.         erasec = sb.sg_erase;
  1296.         killc = sb.sg_kill;
  1297.         werasec = ltc.t_werasc;
  1298.         lnextc = ltc.t_lnextc;
  1299.         rprntc = ltc.t_rprntc;
  1300.     }
  1301.  
  1302.     if (lnextflg) {
  1303.         ch |= 0x80;
  1304.         lnextflg = 0;
  1305.     }
  1306.     (*cnt) --;
  1307.     if (ch == erasec) {
  1308.         if (*cnt < 0)
  1309.             return;
  1310.         fprintf (tty, "\b \b");
  1311.         (*cnt) --;
  1312.         *--cp = 0;
  1313.     } else if (ch == killc) {
  1314.         while (*cnt >= 0) {
  1315.             fprintf (tty, "\b \b");
  1316.             (*cnt) --;
  1317.             *--cp = 0;
  1318.         }
  1319.     } else if (ch == werasec) {
  1320.         if (*cnt < 0)
  1321.             return;
  1322.         while ((cp[-1] == ' ' || cp[-1] == '\t') && (*cnt) >= 0) {
  1323.             fprintf (tty, "\b");
  1324.             (*cnt) --;
  1325.             *--cp = 0;
  1326.         }
  1327.         while (cp[-1] != ' ' && cp[-1] != '\t' && (*cnt) >= 0) {
  1328.             fprintf (tty, "\b \b");
  1329.             (*cnt) --;
  1330.             *--cp = 0;
  1331.         }
  1332.     } else if (ch == lnextc) {
  1333.         lnextflg = 1;
  1334.         fprintf (tty, "^\b");
  1335.     } else if (ch == rprntc) {
  1336.         for (i = strlen (erase_buf); i > 0; i--)
  1337.             putc ('\b', tty);
  1338.         fprintf (tty, "%s", erase_buf);
  1339.     } else {
  1340.         ch &= 0x7f;
  1341.         fprintf (tty, "%c", ch);
  1342.         *cp++ = ch;
  1343.         (*cnt) ++;
  1344.     }
  1345.     fflush (tty);
  1346.     return;
  1347. }
  1348. #endif
  1349. SHAR_EOF
  1350. fi
  1351. echo shar: "extracting 'grabchars.h'" '(553 characters)'
  1352. if test -f 'grabchars.h'
  1353. then
  1354.        echo shar: "will not over-write existing file 'grabchars.h'"
  1355. else
  1356. cat << \SHAR_EOF > 'grabchars.h'
  1357. /*
  1358. **    $Header: grabchars.h,v 1.3 88/12/05 19:46:20 daniel grabchars_1_3 $
  1359. **
  1360. **    grabchars.h - setup for grabchars
  1361. **
  1362. **    Dan Smith (daniel@island.uu.net), November 29, 1988
  1363. */
  1364.  
  1365. struct flag_type {
  1366.     int both;    /* output to stdout and stderr */
  1367.     int check;    /* filter input */
  1368.     int dflt;    /* use following char or string as default */
  1369.     int flush;    /* if set flush input buffer */
  1370.     int ret_key;    /* RETURN key exits when set */
  1371.     int silent;    /* be quiet, just return a status */
  1372.     int erase;    /* DV: honor erase/kill characters */
  1373. };
  1374.  
  1375. typedef struct flag_type FLAG;
  1376. SHAR_EOF
  1377. fi
  1378. exit 0
  1379. #    End of shell archive
  1380.